#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <uart_manager.h>
#include <simple_transimit_receiver.h>

struct uart_task
{
	unsigned int task_id;
	uart_handle handle;
};

struct uart_manager
{
	unsigned int uart_fd;
	int is_uart_opend;
	pthread_mutex_t uart_fd_lock;
	struct uart_task *task_handle;
	unsigned int task_count;
	pthread_t thread;
};

struct uart_task tasks[] = 
{
	{
		.task_id = SIMPLE_TASK, 
		.handle = simple_task_handle
	},
};

struct uart_manager *manager = NULL;
char buffer[512];

static void execute_tasks(const char *buffer)
{
	int loop_i;
	for(loop_i = 0; loop_i < manager->task_count; loop_i++)
	{
		if(buffer[0] == manager->task_handle[loop_i].task_id)
		{
			if(manager->task_handle[loop_i].handle != NULL)
			{
				manager->task_handle[loop_i].handle(buffer);
			}
		}
	}
}

static void *uart_manager_recv(void *arg)
{
	//assert(NULL != arg);
	//struct uart_manager *manager = (struct uart_manager *)arg;
	int retval = 0;
	ssize_t rd_num;
	while(1)
	{
		
		memset(buffer, 0, 512);
		pthread_mutex_lock(&manager->uart_fd_lock);
		rd_num = read(manager->uart_fd, buffer, 50);
		pthread_mutex_unlock(&manager->uart_fd_lock);
		if(rd_num > 0){
			//uart_manager_send(buffer, rd_num);
			execute_tasks(buffer);
		}
	}

	pthread_exit(&retval);
}

void uart_pthread_wait_exit()
{
	int *retval;
	printf("waiting recv thread exit...\n");
	pthread_join(manager->thread, (void **)&retval);
	printf("recv thread exited\n");
}

int uart_manager_send(const char *buffer, unsigned int count)
{
	ssize_t snd_num = 0;
	char buf[512]="";
	if(buffer != NULL && count > 0)
	{
		memcpy(buf, buffer, count);
		pthread_mutex_lock(&manager->uart_fd_lock);
		snd_num = write(manager->uart_fd, buf,count );
		pthread_mutex_unlock(&manager->uart_fd_lock);
		if(snd_num < 0)
		{
			printf("send data failed -2!!!\n");
			return -2;
		}
	}
	else
	{
		printf("send data failed -1!!!\n");
		return -1;
	}

	return snd_num;
}

static void uart_free_manager()
{
	if(NULL != manager)
	{
		free(manager);
		manager = NULL;
	}
}

static int uart_init_manager(const int uart_fd)
{
	manager = (struct uart_manager *)malloc(sizeof(struct uart_manager));
	if( NULL == manager)
	{
		printf("malloc failed!!!\n");
		return -1;
	}

	manager->uart_fd = uart_fd;
	if(0 != pthread_mutex_init(&manager->uart_fd_lock,NULL))
	{
		printf("init mutex failed!!!\n");
		uart_free_manager(manager);
		return -2;
	}

	manager->task_handle = tasks;
	manager->task_count = sizeof(tasks) / sizeof(tasks[0]);
	if(pthread_create(&manager->thread, NULL,uart_manager_recv, NULL) < 0)
	{
		printf("pthread_create failed!!!\n");
		uart_free_manager(manager);
		return -3;
	}

	manager->is_uart_opend = 1;
	return 0;
}


static int uart_set(const int uart_fd, int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio,oldtio;
	if  ( tcgetattr(uart_fd,&oldtio)  !=  0) { 
		perror("SetupSerial 1");
		return -1;
	}
	bzero( &newtio, sizeof( newtio ) );
	newtio.c_cflag  |=  CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;

	switch( nBits )
	{
		case 7:
			newtio.c_cflag |= CS7;
			break;
		case 8:
			newtio.c_cflag |= CS8;
			break;
	}


	switch( nEvent )
	{
		case 'O':
			newtio.c_cflag |= PARENB;
			newtio.c_cflag |= PARODD;
			newtio.c_iflag |= (INPCK | ISTRIP);
			break;
		case 'E': 
			newtio.c_iflag |= (INPCK | ISTRIP);
			newtio.c_cflag |= PARENB;
			newtio.c_cflag &= ~PARODD;
			break;
		case 'N':  
			newtio.c_cflag &= ~PARENB;
			break;
	}

	switch( nSpeed )
	{
		case 2400:
			cfsetispeed(&newtio, B2400);
			cfsetospeed(&newtio, B2400);
			break;
		case 4800:
			cfsetispeed(&newtio, B4800);
			cfsetospeed(&newtio, B4800);
			break;
		case 9600:
			cfsetispeed(&newtio, B9600);
			cfsetospeed(&newtio, B9600);
			break;
		case 115200:
			cfsetispeed(&newtio, B115200);
			cfsetospeed(&newtio, B115200);
			break;
		case 460800:
			cfsetispeed(&newtio, B460800);
			cfsetospeed(&newtio, B460800);
			break;
		default:
			cfsetispeed(&newtio, B9600);
			cfsetospeed(&newtio, B9600);
			break;
	}

	if( nStop == 1 )
		newtio.c_cflag &=  ~CSTOPB;
	else if ( nStop == 2 )
		newtio.c_cflag |=  CSTOPB;
	newtio.c_cc[VTIME]  = 0;
	newtio.c_cc[VMIN] = 0;
	tcflush(uart_fd,TCIFLUSH);
	if((tcsetattr(uart_fd,TCSANOW,&newtio))!=0)
	{
		perror("com set error");
		return -2;
	}
	return 0;
}

static int uart_internal_close(const int fd)
{
	close(fd);
	return 0;
}

int uart_open(const char *uart_name)
{
	assert(NULL != uart_name);

	int fd = open(uart_name, O_RDWR|O_NOCTTY|O_NDELAY);
	if(fd < 0)
	{
		printf("UART MANAGER: open uart: %s failed\n", uart_name);
		return -1;
	}
	else
	{
		printf("UART MANAGER: open uart : %s sucessfully\n", uart_name);
	}

	if(uart_set(fd, 115200, 8, 'N', 1) < 0)
	{
		printf("UART MANAGER: set uart options failed!!!\n");
		uart_internal_close(fd);
		return -2;
	}
	else
	{
		printf("UART MANAGER: SET OPTIONS sucessfully\n");
	}

	if(uart_init_manager(fd) < 0)
	{
		printf("init uart manager failed!!!\n");
		uart_internal_close(fd);
		return -3;
	}
	else
	{
		printf("UART MANAGER: uart init manager sucessfully\n");
	}
	
	uart_manager_send("Open sucessfully", strlen("Open sucessfully"));
	return 0;
}


int uart_close()
{
	if(manager->is_uart_opend == 1)
	{
		pthread_mutex_lock(&manager->uart_fd_lock);
		close(manager->uart_fd);
		pthread_mutex_unlock(&manager->uart_fd_lock);
		manager->is_uart_opend = 0;
	}
	return 0;
}
